﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Threading;

namespace ServerRPG
{
    class CreatureManager
    {
        // Load creatures from DB and manage them.
        public List<Creature> creatureList = new List<Creature>();

        private List<Creature> creaturesTimers = new List<Creature>();
        private Thread respawnThread;

        public CreatureManager()
        {
            DataTable creatures = DBManager.Select("SELECT id, creatureID, zoneID, x, y, spawnTime FROM SpawnPoints");
            if (creatures.Rows.Count > 0)
            {
                for (int i = 0; i < creatures.Rows.Count; i++)
                {
                    int id = 0, creatureId = 0, zoneId = 0, x = 0, y = 0, time = 0;
                    int.TryParse(creatures.Rows[i][0].ToString(), out id);
                    int.TryParse(creatures.Rows[i][1].ToString(), out creatureId);
                    int.TryParse(creatures.Rows[i][2].ToString(), out zoneId);
                    int.TryParse(creatures.Rows[i][3].ToString(), out x);
                    int.TryParse(creatures.Rows[i][4].ToString(), out y);
                    int.TryParse(creatures.Rows[i][5].ToString(), out time);
                    creatureList.Add(new Creature(id, creatureId, zoneId, x, y, time));
                }
            }
            foreach (Creature c in creatureList)
                c.Respawn();

            respawnThread = new Thread(RespawnThread);
            respawnThread.Start();
        }
        public void Stop()
        {
            if (respawnThread != null)
                respawnThread.Abort();
        }

        public void AdjustHitPoints(int id, int value)
        {
            Creature c = creatureList.Find(p => p.id == id);
            c.AdjustHitPoints(value);
            if (c.GetState() == State.dead)
            {
                c.RespawnUpdateDate();
                creaturesTimers.Add(c);
            }
        }

        private void RespawnThread()
        {
            while (true)
            {
                if (creaturesTimers.Count != 0)
                {
                    foreach (Creature c in creaturesTimers)
                    {
                        if (c.spawnDate <= DateTime.Now)
                        {
                            c.Respawn();
                            creaturesTimers.Remove(c);
                        }
                    }
                }

                Thread.Sleep(1000); // 1 sec.
            }
        }
    }

    public enum State
    {
        dead = 0,
        normal = 1
    }

    class Creature
    {
        public readonly string name;

        public int id = 0;
        private int _creatureId = 0;
        private byte _currentState = (byte) State.normal;

        public int _currentX = 0;
        public int _currentY = 0;

        private int _spawnX = 0;
        private int _spawnY = 0;
        private int _spawnZone = 0;
        private int _spawnTime = 0; // Seconds.
        public DateTime spawnDate; 

        private int _maxHitPoints = 0;
        private int _currentHitPoints = 0;

        public Creature(int id, int creatureId, int spawnZone, int spawnX, int spawnY, int spawnTime)
        {
            this.id = id;
            _creatureId = creatureId;
            _spawnZone = spawnZone;
            _spawnX = spawnX;
            _spawnY = spawnY;
            _spawnTime = spawnTime;

            // Load stats.
            DataTable stats = DBManager.Select("SELECT name, hitPoints FROM Creatures WHERE id = " + creatureId);
            if (stats.Rows.Count > 0)
            {
                name = stats.Rows[0][0].ToString();
                int.TryParse(stats.Rows[0][1].ToString(), out _maxHitPoints);
            }
            else
                throw new Exception("Cannot load creature stats with id = " + creatureId);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <returns>Returns creature state. 'Ok' or not.</returns>
        public void AdjustHitPoints(int value)
        {
            _currentHitPoints += value;
            if (_currentHitPoints > _maxHitPoints)
                _currentHitPoints = _maxHitPoints;
            else
                if (_currentHitPoints <= 0)
                    SetState(State.dead);
        }
        public void SetHitPoints(int value)
        {
            if (value >= 0 && value <= _maxHitPoints)
                _currentHitPoints = value;
            else
                throw new Exception("Hit points can't be less than 0 or more than max hit points.");
        }

        public void SetState(State state)
        {
            _currentState = (byte) state;
        }
        public State GetState()
        {
            return (State) _currentState;
        }
        public void Respawn()
        {
            _currentState = (byte) State.normal;
            _currentX = _spawnX;
            _currentY = _spawnY;
            _currentHitPoints = _maxHitPoints;
        }
        public void RespawnUpdateDate()
        {
            spawnDate = DateTime.Now.AddSeconds(_spawnTime);
        }
    }
}
